// Controller.m

#import "Controller.h"

@implementation Controller

- (void)addPrimal:(NXPoint)point
{
	if ([enterMode selectedRow] == 0) {	// in point mode
		if (numberOfPrimalPoints >= MAX_POINTS) {
			NXRunAlertPanel("Error", "Too many points", NULL, NULL, NULL);
			return;
		}
		sprintf(primalPoint[numberOfPrimalPoints].label, "%d", labelCounter++);
		primalPoint[numberOfPrimalPoints].color = [pointColorWell color];
		primalPoint[numberOfPrimalPoints].a = point.x;
		primalPoint[numberOfPrimalPoints++].b = point.y;
		[pointBrowser loadColumnZero];
	} else {
		if (numberOfPrimalLines >= MAX_POINTS) {
			NXRunAlertPanel("Error", "Too many lines", NULL, NULL, NULL);
			return;
		}
		if (!enter2) {
			point1 = point;
			enter2 = YES;
		} else {
			float a;
			
			enter2 = NO;
			if (point.x == point1.x) {
				NXRunAlertPanel("Error", "Can't have a vertical line", NULL, NULL, NULL);
				return;
			}
			a = (point.y - point1.y) / (point.x - point1.x);
			sprintf(primalLine[numberOfPrimalLines].label, "%d", labelCounter++);
			primalLine[numberOfPrimalLines].color = [lineColorWell color];
			primalLine[numberOfPrimalLines].a = a;
			primalLine[numberOfPrimalLines++].b = point.y - a * point.x;
			[lineBrowser loadColumnZero];
		}
	}
	
	[self draw:self];
}

- (void)addDual:(NXPoint)point
{
	if ([enterMode selectedRow] == 0) {	// in point mode
		// a point in the dual plane corresponds to a line in the primal plane
		if (numberOfPrimalLines >= MAX_POINTS) {
			NXRunAlertPanel("Error", "Too many lines", NULL, NULL, NULL);
			return;
		}
		sprintf(primalLine[numberOfPrimalLines].label, "%d", labelCounter++);
		primalLine[numberOfPrimalLines].color = [pointColorWell color];
		primalLine[numberOfPrimalLines].a = point.x;
		primalLine[numberOfPrimalLines++].b = -point.y;
		[lineBrowser loadColumnZero];
	} else {
		// a line in the dual plane corresponds to a point in the primal plane
		if (numberOfPrimalPoints >= MAX_POINTS) {
			NXRunAlertPanel("Error", "Too many points", NULL, NULL, NULL);
			return;
		}
		if (!enter2) {
			point1 = point;
			enter2 = YES;
		} else {
			float a;
			
			enter2 = NO;
			if (point.x == point1.x) {
				NXRunAlertPanel("Error", "Can't have a vertical line", NULL, NULL, NULL);
				return;
			}
			a = (point.y - point1.y) / (point.x - point1.x);
			sprintf(primalPoint[numberOfPrimalPoints].label, "%d", labelCounter++);
			primalPoint[numberOfPrimalPoints].color = [lineColorWell color];
			primalPoint[numberOfPrimalPoints].a = a;
			primalPoint[numberOfPrimalPoints++].b = -(point.y - a * point.x);
			[pointBrowser loadColumnZero];
		}
	}
	
	[self draw:self];
}

- (int)browser:sender fillMatrix:matrix inColumn:(int)column
{
	int row;
	id cell;
	char buf[1000];
	
	if (sender == pointBrowser) {
		for (row = 0; row < numberOfPrimalPoints; row++) {
			[matrix addRow];
			cell = [matrix cellAt:row :0];
			sprintf(buf, "%s: (%.2f,%.2f)", primalPoint[row].label, primalPoint[row].a,
				primalPoint[row].b);
			[cell setStringValue:buf];
			[cell setLoaded:YES];
			[cell setLeaf:YES];
		}
		return row;
	} else {
		for (row = 0; row < numberOfPrimalLines; row++) {
			[matrix addRow];
			cell = [matrix cellAt:row :0];
			sprintf(buf, "%s: y = %.2f * x + %.2f", primalLine[row].label, 
				primalLine[row].a, primalLine[row].b);
			[cell setStringValue:buf];
			[cell setLoaded:YES];
			[cell setLeaf:YES];
		}
		return row;
	}
}

- (void)getPrimalPoints:(int *)num :(PointLine **)point;
{
	*num = numberOfPrimalPoints;
	*point = primalPoint;
}

- (void)getPrimalLines:(int *)num :(PointLine **)line;
{
	*num = numberOfPrimalLines;
	*line = primalLine;
}

- deletePoint:sender
{
	Matrix *m = [pointBrowser matrixInColumn:0];
	if ([m selectedRow] != -1) {
		int i;
		for (i = [m selectedRow]; i < numberOfPrimalPoints - 1; i++)
			primalPoint[i] = primalPoint[i+1];
		numberOfPrimalPoints--;
		[self draw:self];
		[pointBrowser loadColumnZero];
	}
	return self;
}

- deleteAllPoints:sender
{
	numberOfPrimalPoints = 0;
	[self draw:self];
	[pointBrowser loadColumnZero];
	return self;
}

- deleteLine:sender
{
	Matrix *m = [lineBrowser matrixInColumn:0];
	if ([m selectedRow] != -1) {
		int i;
		for (i = [m selectedRow]; i < numberOfPrimalLines - 1; i++)
			primalLine[i] = primalLine[i+1];
		numberOfPrimalLines--;
		[self draw:self];
		[lineBrowser loadColumnZero];
	}
	return self;
}

- deleteAllLines:sender
{
	numberOfPrimalLines = 0;
	[self draw:self];
	[lineBrowser loadColumnZero];
	return self;
}

- draw:sender
{
	[primalPlaneView display];
	[dualPlaneView display];
	return self;
}

- newPointLabel:sender
{
	Matrix *m = [pointBrowser matrixInColumn:0];
	int row = [m selectedRow];
	if (row != -1 && [pointLabel stringValue])
		strcpy(primalPoint[row].label, [pointLabel stringValue]);
	[self draw:self];
	[pointBrowser loadColumnZero];
	return self;
}

- newLineLabel:sender
{
	Matrix *m = [lineBrowser matrixInColumn:0];
	int row = [m selectedRow];
	if (row != -1 && [lineLabel stringValue])
		strcpy(primalLine[row].label, [lineLabel stringValue]);
	[self draw:self];
	[lineBrowser loadColumnZero];
	return self;
}

- pointSelected:sender
{
	Matrix *m = [pointBrowser matrixInColumn:0];
	int row = [m selectedRow];
	if (row != -1)
		[pointLabel setStringValue:primalPoint[row].label];
	return self;
}

- lineSelected:sender
{
	Matrix *m = [lineBrowser matrixInColumn:0];
	int row = [m selectedRow];
	if (row != -1)
		[lineLabel setStringValue:primalLine[row].label];
	return self;
}

- newPointColor:sender
{
	Matrix *m = [pointBrowser matrixInColumn:0];
	int row = [m selectedRow];
	if (row != -1) {
		primalPoint[row].color = [pointColorWell color];
		[self draw:self];
	}
	return self;
}

- newLineColor:sender
{
	Matrix *m = [lineBrowser matrixInColumn:0];
	int row = [m selectedRow];
	if (row != -1) {
		primalLine[row].color = [lineColorWell color];
		[self draw:self];
	}
	return self;
}

- showInfo:sender
{
    if (!infoPanel)
		infoPanel = [NXApp loadNibSection:"InfoPanel.nib" owner:self];
    [infoPanel makeKeyAndOrderFront:self];
    return self;	
}

#define MAIL_ADDRESS "rgc@cs.umd.edu"
#define SUBJECT "Suggestion/Bug for Dual"

- suggestion:sender
{
	id s = [NXApp appSpeaker];

	NXPortFromName("Mail", NULL); // make sure app is launched
	[[NXApp appSpeaker] setSendPort:NXPortFromName("MailSendDemo", NULL)];
	[s performRemoteMethod:"setTo:" with:MAIL_ADDRESS length:strlen(MAIL_ADDRESS)+1];
	[s performRemoteMethod:"setSubject:" with:SUBJECT length:strlen(SUBJECT)+1];
	return self;
}

@end
